import yaml
import json
from typing import Dict, Any, Callable

class DataParser:
    def __init__(self, config_path: str = "config/parser_config.yaml"):
        # 加载所有数据格式的解析配置（来自config文件）
        self.config = self._load_config(config_path)
        # 注册所有支持的解析函数（新增格式只需在这里添加映射）
        self.parser_registry = self._register_all_parsers()

    def _load_config(self, config_path: str) -> Dict[str, Any]:
        """加载配置文件（处理异常）"""
        try:
            with open(config_path, "r", encoding="utf-8") as f:
                return yaml.safe_load(f)
        except FileNotFoundError:
            raise FileNotFoundError(f"配置文件不存在：{config_path}，请先创建")
        except yaml.YAMLError as e:
            raise ValueError(f"配置文件格式错误：{str(e)}")

    def _register_all_parsers(self) -> Dict[str, Callable]:
        """解析函数注册表：key=数据类型（与config一致），value=对应的解析函数"""
        return {
            "sensor_json": self._parse_json,    # JSON格式
            "csv_log": self._parse_csv,        # CSV格式
            "image_binary": self._parse_image_binary,  # 图像二进制
            "gps_nmea": self._parse_gps_nmea,  # 新增GPS NMEA格式
            # 后续新增格式：只需在这里添加「数据类型: 解析函数」映射，无需改其他代码
        
        }

    def parse(self, raw_data: bytes, data_type: str) -> Dict[str, Any]:
        """核心解析入口：动态匹配解析函数（无需硬编码判断）"""
        # 1. 检查数据类型是否在配置中定义
        if data_type not in self.config:
            raise ValueError(f"未找到{data_type}的配置，请在config/parser_config.yaml中添加")
        # 2. 检查数据类型是否已注册解析函数
        if data_type not in self.parser_registry:
            raise ValueError(f"未注册{data_type}的解析函数，请在_parser_registry中添加映射")
        
        # 3. 动态调用对应的解析函数，传入原始数据和配置
        return self.parser_registry[data_type](raw_data, self.config[data_type])


    # 以下是具体解析函数（独立封装，可按需扩展）

    def _parse_json(self, raw_data: bytes, config: Dict) -> Dict[str, Any]:
        """JSON格式解析逻辑"""
        data_dict = json.loads(raw_data.decode(config.get("encoding", "utf-8")))
        # 检查必填字段
        missing_fields = [f for f in config["required_fields"] if f not in data_dict]
        if missing_fields:
            raise KeyError(f"缺失必填字段：{missing_fields}")
        return {f: data_dict[f] for f in config["required_fields"]}

    def _parse_csv(self, raw_data: bytes, config: Dict) -> Dict[str, Any]:
        """CSV格式解析逻辑"""
        header = config["header"].split(config.get("delimiter", ","))
        csv_rows = raw_data.decode(config.get("encoding", "utf-8")).split("\n")
        parsed_rows = []
        for row in csv_rows:
            row = row.strip()
            if not row:
                continue  # 过滤空行
            row_data = row.split(config.get("delimiter", ","))
            if len(row_data) != len(header):
                raise ValueError(f"CSV行数据长度不匹配：{row}（预期{len(header)}列，实际{len(row_data)}列）")
            parsed_rows.append(dict(zip(header, row_data)))
        return {"rows": parsed_rows}

    def _parse_image_binary(self, raw_data: bytes, config: Dict) -> Dict[str, Any]:
        """图像二进制解析逻辑"""
        return {
            "image_size_bytes": len(raw_data),
            "timestamp": config["timestamp_field"],
            "format": config.get("format", "unknown")
        }

    def _parse_gps_nmea(self, raw_data: bytes, config: Dict) -> Dict[str, Any]:
        """新增GPS NMEA格式解析函数"""
        # NMEA协议示例数据：$GPGGA,085546.00,3958.3032,N,11623.2756,E,1,08,1.0,73.7,M,-9.5,M,,*57
        text_data = raw_data.decode(config.get("encoding", "utf-8")).strip()
        
        # 验证是否为目标NMEA语句（如$GPGGA）
        if not text_data.startswith(config["sentence_type"]):
            raise ValueError(f"不是目标NMEA语句，预期{config['sentence_type']}，实际{text_data[:6]}")
        
        # 按逗号分割字段（NMEA协议默认分隔符）
        fields = text_data.split(",")
        # 提取配置中定义的必填字段（如纬度、经度、海拔）
        parsed_data = {}
        for field_name, field_index in config["field_mapping"].items():
            if len(fields) <= field_index:
                raise ValueError(f"NMEA语句字段不足，无法提取{field_name}（索引{field_index}）")
            parsed_data[field_name] = fields[field_index]
        
        return parsed_data

    # 新增其他格式示例：如需支持视频二进制，复制以下模板修改
    # def _parse_video_binary(self, raw_data: bytes, config: Dict) -> Dict[str, Any]:
    #     """视频二进制格式解析（示例模板）"""
    #     return {
    #         "video_duration": config.get("duration", 0),
    #         "video_size_bytes": len(raw_data),
    #         "codec": config.get("codec", "h264")
    #     }